package com.superbytecode.cloud.web.swagger;

import com.fasterxml.jackson.databind.introspect.AnnotatedField;
import com.fasterxml.jackson.databind.introspect.BeanPropertyDefinition;
import lombok.extern.slf4j.Slf4j;
import org.hibernate.validator.internal.engine.messageinterpolation.InterpolationTermType;
import org.hibernate.validator.internal.engine.messageinterpolation.parser.TokenCollector;
import org.hibernate.validator.internal.engine.messageinterpolation.parser.TokenIterator;
import org.hibernate.validator.resourceloading.PlatformResourceBundleLocator;
import org.springframework.core.annotation.AnnotationUtils;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spi.schema.ModelPropertyBuilderPlugin;
import springfox.documentation.spi.schema.contexts.ModelPropertyContext;

import javax.validation.Constraint;
import java.lang.annotation.Annotation;
import java.util.Locale;
import java.util.Map;
import java.util.ResourceBundle;
import java.util.StringJoiner;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
 * All rights Reserved, Designed By www.super-master.com
 *
 * @ProjectName: beacon-cloud
 * @Package: com.superbytecode.cloud.web.swagger
 * @ClassName: PropertyBuilderValidatePlugin
 * @Description: [Swagger基于validation注解生成 提示文档]
 * <p> </p>
 * @Author: [Lance Ting]
 * @Date: 2024/10/22 12:00
 * @Version: V1.0
 * @Copyright: 2024 www.super-master.com Inc. All rights reserved.
 * TODO: 注意,本文件Lance Ting所作,如果转载或使用请标明具体出处!
 **/
@Slf4j
public class PropertyBuilderValidatePlugin implements ModelPropertyBuilderPlugin {
    private final PlatformResourceBundleLocator platformResourceBundleLocator = new PlatformResourceBundleLocator("org.hibernate.validator.ValidationMessages");
    private final ResourceBundle defaultResourceBundle = platformResourceBundleLocator.getResourceBundle(Locale.CHINA);

    /**
     * @param context context
     */
    @Override
    public void apply(ModelPropertyContext context) {
        try {
            context.getBeanPropertyDefinition().map(BeanPropertyDefinition::getField).map(AnnotatedField::getAnnotated)//
                    .ifPresent(field -> {
                        Annotation[] annotations = field.getAnnotations();
                        StringJoiner stringJoiner = new StringJoiner(",", "ℹ️ ", "");
                        Stream.of(annotations).filter(annotation -> annotation.annotationType().isAnnotationPresent(Constraint.class))//
                                .map(this::annotationAppendMessage).collect(Collectors.toList()).forEach(annotation -> {//
                                    stringJoiner.add((CharSequence) annotationAppendMessage((Annotation) annotation));
                                });
                        String message = stringJoiner.toString();
                        if (message.isEmpty()) {
                            return;
                        }
                        SwaggerUtil.append(context, "<br><span style='color:#2067ae'>" + message + "</span>");
                    });
        } catch (Exception e) {
            log.error("validation注解描述追加失败", e);
        }
    }

    /**
     * @param documentationType 类型
     * @return 标识
     */
    @Override
    public boolean supports(DocumentationType documentationType) {
        return true;
    }

    private Object annotationAppendMessage(Annotation annotation) {
        Map<String, Object> annotationAttributes = AnnotationUtils.getAnnotationAttributes(annotation);
        String message = annotationAttributes.get("message").toString();
        if (message.indexOf("{") != 0) {
            return message;
        }
        String resolvedMessage = defaultResourceBundle.getString(removeCurlyBraces(message));
        TokenCollector tokenCollector = new TokenCollector(resolvedMessage, InterpolationTermType.PARAMETER);
        TokenIterator tokenIterator = new TokenIterator(tokenCollector.getTokenList());
        while (tokenIterator.hasMoreInterpolationTerms()) {
            String term = tokenIterator.nextInterpolationTerm();
            String resolvedExpression = annotationAttributes.get(removeCurlyBraces(term)).toString();
            tokenIterator.replaceCurrentInterpolationTerm(resolvedExpression);
        }
        return tokenIterator.getInterpolatedMessage();
    }

    private String removeCurlyBraces(String parameter) {
        return parameter.substring(1, parameter.length() - 1);
    }

}